// 创建父子进程，在子进程中向无名管道中写入”helloworld”，在父进程中读出。
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

using namespace std;

int main()
{
    int pipefd[2];    // pipefd[0] 为读端, pipefd[1] 为写端
    char buffer[100]; // 用于存储读取的数据

    // 创建无名管道
    if (pipe(pipefd) == -1)
    {
        perror("pipe");
        exit(-1);
    }

    // 创建子进程
    pid_t pid = fork();

    if (pid < 0)
    {
        perror("fork");
        exit(-1); // fork 失败
    }
    else if (pid == 0)
    {
        // 子进程
        close(pipefd[0]); // 关闭读端

        const char *message = "helloworld";         // 要写入管道的消息
        write(pipefd[1], message, strlen(message)); // 向管道写入消息
        close(pipefd[1]);                           // 关闭写端
        _exit(0);                                   // 结束子进程
    }
    else
    {
        // 父进程
        close(pipefd[1]); // 关闭写端
        // 父进程和子进程都需要独立地关闭不需要的管道端口，因为它们各自持有独立的文件描述符副本
        // 在父进程和子进程之间，尽管它们共享文件描述符（包括管道的文件描述符）
        // 但每个进程都有自己的文件描述符副本。
        // 因此，管道在父子进程中表现为两个独立的文件描述符集合：父进程有一套，子进程也有一套

        // 读取管道中的数据
        size_t readBytes = read(pipefd[0], buffer, sizeof(buffer) - 1);
        if (readBytes > 0)
        {
            buffer[readBytes] = '\0';                                  // 添加字符串结束符
            cout << "Received from child process: " << buffer << endl; // 输出接收到的数据
        }
        else
        {
            perror("read");
        }
        close(pipefd[0]); // 关闭读端

        wait(nullptr); // 等待子进程结束（良好习惯：避免僵尸进程）
    }

    return 0;
}